﻿/*
   Open Intel 
   Copyright © 2011 – ISC. All Rights Reserved.
*/

using System;
using System.Windows.Threading;
using ISC.MapDotNetServer.Common;
using ISC.RIM.Silverlight;
using ISC.RIM.Silverlight.ShapeEditing;

namespace OI.Framework
{
    public class MeasurementManager
    {
        #region DATA
        public ITileProjection Projection { get; private set; }
        public Action<string> SetMeasurement { get; private set; }
        public ShapeEditManager ShapeEditor { get; private set; }


        public DispatcherTimer ChangeTimer
        {
            get
            {
                if (_ChangeTimer == null)
                {
                    _ChangeTimer = new DispatcherTimer();
                    _ChangeTimer.Interval = TimeSpan.FromSeconds(0.25);
                    _ChangeTimer.Tick += new EventHandler(ChangeTimerTick);
                }
                return _ChangeTimer;
            }
        }
        private DispatcherTimer _ChangeTimer;

        /// <summary>
        /// Gets or sets the length units for measurement.
        /// </summary>
        /// <value>The length units to use when ShowMeasurements is 'true'.</value>
        public Units.Length LengthUnits
        {
            get { return _LengthUnits; }
            set
            {
                if (_LengthUnits != value)
                {
                    _LengthUnits = value;
                    Update();
                }
            }
        }
        private Units.Length _LengthUnits = Units.Length.Meters;

        /// <summary>
        /// Gets or sets the area units for measurement.
        /// </summary>
        /// <value>The area units to use when ShowMeasurements is 'true'.</value>
        public Units.Area AreaUnits
        {
            get { return _AreaUnits; }
            set
            {
                if (_AreaUnits != value)
                {
                    _AreaUnits = value;
                    Update();
                }
            }
        }
        private Units.Area _AreaUnits = Units.Area.Meters_sq;


        #endregion

        // constructor bridges action to write string to output and input function for map units per pixel along with the ShapeEditManager
        public MeasurementManager(
            ITileProjection projection,
            Action<string> setMeasurement, 
            ShapeEditManager shapeEditor)
        {
            Projection = projection;
            SetMeasurement = setMeasurement;
            ShapeEditor = shapeEditor;

            ShapeEditor.ShapeChanged += ShapeChanged;
        }


        // unwire and stop this instance
        public void Disconnect()
        {
            ShapeEditor.ShapeChanged -= ShapeChanged;
            ChangeTimer.Stop();
        }


        // select next unit types
        public void NextUnits()
        {
            int idx = (int)LengthUnits + 1;
            if (idx >= Units._NumberOfUnitTypes)
            {
                idx = 0;
            }
            LengthUnits = (Units.Length)idx;
            AreaUnits = (Units.Area)idx;
        }


        // used to prevent rapid searches on typing
        private void ChangeTimerTick(object sender, EventArgs e)
        {
            ChangeTimer.Stop();

            // here's where we will sample measurements
            Update();
        }


        // handle shape changes and show measurements
        private void ShapeChanged(object sender, ISC.RIM.Silverlight.ShapeEditing.ShapeChangeEventArgs e)
        {
            if (e.AffectedParts.Count > 0)
            {
                ChangeTimer.Start();
            }
        }


        private void Update()
        {
            string output = "";

            // get the current map units per pixel
            double mapUnitsPerMeter = Projection.GetMapUnitsPerMeter();

            if (ShapeEditor is PolygonEditor)
            {
                var pe = (PolygonEditor)ShapeEditor;
                var poly = pe.GetPolygonSnapshot();

                if (poly != null)
                {
                    // transform based on projection
                    var transShape = Units.CopyTransformForMeasurement(poly, Projection);
                    var polygon = new Polygon(transShape);

                    double area = Units.ComputeArea(polygon.GetArea(), mapUnitsPerMeter, AreaUnits);
                    double perim = Units.ComputeLength(polygon.GetPerimeter(), mapUnitsPerMeter, LengthUnits);

                    output = "Area: " + area.ToString("N2") + " " + AreaUnits + "\nPerimeter: " + perim.ToString("N2") + " " + LengthUnits;
                }
            }
            else if (ShapeEditor is PolylineEditor)
            {
                var pe = (PolylineEditor)ShapeEditor;
                var poly = pe.GetPolylineSnapshot();

                if (poly != null)
                {
                    // transform based on projection
                    var transShape = Units.CopyTransformForMeasurement(poly, Projection);
                    var polyline = new Polyline(transShape);

                    double dist = Units.ComputeLength(polyline.GetDistance(), mapUnitsPerMeter, LengthUnits);

                    output = "Total Length: " + dist.ToString("N2") + " " + LengthUnits;
                }
            }

            SetMeasurement(output);
        }
    }
}
